/**
 * @file scd4x.cpp
 * @brief Implementation of SCD4X CO2 sensor driver for ESP32 IDF
 * @author CodeBuddy
 * @version 1.1
 * @date 2025-09-12
 */

#include "scd4x.h"
#include <esp_log.h>
#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <cstdio>
#include <ctime>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
// #include "sdcard_bsp.h"

// Add missing SDMMC headers


#define TAG "SCD4X"

// CRC constants
#define SCD4X_CRC8_INIT       0xFF
#define SCD4X_CRC8_POLYNOMIAL 0x31

SCD4X::SCD4X(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) {
    // Initialize default log path
 
}

bool SCD4X::begin() {
    // First, make sure the sensor is awake
    setSleepMode(false);
    
    // Wait a bit more after wake-up to ensure sensor is ready
    vTaskDelay(pdMS_TO_TICKS(100));
    
    // Try to stop any ongoing measurements first
    try {
        uint8_t stop_cmd[2] = {
            (uint8_t)((SCD4X_STOP_PERIODIC_MEASURE >> 8) & 0xFF),
            (uint8_t)(SCD4X_STOP_PERIODIC_MEASURE & 0xFF)
        };
        i2c_master_transmit(i2c_device_, stop_cmd, 2, 1000);
        vTaskDelay(pdMS_TO_TICKS(50));
    } catch (...) {
        // If stopping fails, just continue - sensor might not have been measuring
    }
    
    // Now start periodic measurement
    enablePeriodMeasure(SCD4X_MODE_PERIODIC);
    // enablePeriodMeasure(SCD4X_MODE_LOW_POWER);
    ESP_LOGI(TAG, "SCD4X initialized successfully");
    return true;
}

void SCD4X::setSleepMode(bool sleep) {
    // For wake-up, we need to send the command in a special way
    if (!sleep) {
        // Wake-up command is special - it uses a different approach
        // Create a command buffer with the wake-up command
        uint8_t wakeup_cmd[2] = {
            (uint8_t)((SCD4X_WAKE_UP >> 8) & 0xFF),
            (uint8_t)(SCD4X_WAKE_UP & 0xFF)
        };
        // Use i2c_master_transmit directly with a longer timeout
        i2c_master_transmit(i2c_device_, wakeup_cmd, 2, 1000);
        vTaskDelay(pdMS_TO_TICKS(20)); // Required 20ms delay after wake-up
    } else {
        // For sleep mode, use the standard approach but with longer timeout
        uint8_t sleep_cmd[2] = {
            (uint8_t)((SCD4X_POWER_DOWN >> 8) & 0xFF),
            (uint8_t)(SCD4X_POWER_DOWN & 0xFF)
        };
        i2c_master_transmit(i2c_device_, sleep_cmd, 2, 1000);
    }
}

uint16_t SCD4X::performSelfTest() {
    // Send the self-test command
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_PERFORM_SELF_TEST >> 8) & 0xFF),
        (uint8_t)(SCD4X_PERFORM_SELF_TEST & 0xFF)
    };
    
    esp_err_t result = i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending self-test command: %d", result);
        return 0xFFFF;
    }
    
    // Self-test takes up to 10 seconds
    vTaskDelay(pdMS_TO_TICKS(10000));
    
    // Send the read command to get the result
    uint8_t read_cmd[2] = {
        (uint8_t)((SCD4X_READ_MEASUREMENT >> 8) & 0xFF),
        (uint8_t)(SCD4X_READ_MEASUREMENT & 0xFF)
    };
    
    result = i2c_master_transmit(i2c_device_, read_cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending read command for self-test result: %d", result);
        return 0xFFFF;
    }
    
    // Wait a bit before reading
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // Read 3 bytes: result (2 bytes) and CRC
    uint8_t data[3];
    result = i2c_master_receive(i2c_device_, data, 3, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error reading self-test result: %d", result);
        return 0xFFFF;
    }
    
    if (calcCRC8(&data[0], 2) != data[2]) {
        ESP_LOGE(TAG, "CRC check failed for self-test result");
        return 0xFFFF;
    }
    
    return (uint16_t)((data[0] << 8) | data[1]);
}

void SCD4X::moduleReinit() {
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_REINIT >> 8) & 0xFF),
        (uint8_t)(SCD4X_REINIT & 0xFF)
    };
    i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    vTaskDelay(pdMS_TO_TICKS(20));
}

void SCD4X::performFactoryReset() {
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_PERFORM_FACTORY_RESET >> 8) & 0xFF),
        (uint8_t)(SCD4X_PERFORM_FACTORY_RESET & 0xFF)
    };
    i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    vTaskDelay(pdMS_TO_TICKS(1200));
}

void SCD4X::measureSingleShot(bool rht_only) {
    uint8_t cmd[2];
    
    if (rht_only) {
        cmd[0] = (uint8_t)((SCD4X_MEASURE_SINGLE_SHOT_RHT_ONLY >> 8) & 0xFF);
        cmd[1] = (uint8_t)(SCD4X_MEASURE_SINGLE_SHOT_RHT_ONLY & 0xFF);
        i2c_master_transmit(i2c_device_, cmd, 2, 1000);
        vTaskDelay(pdMS_TO_TICKS(50));
    } else {
        cmd[0] = (uint8_t)((SCD4X_MEASURE_SINGLE_SHOT >> 8) & 0xFF);
        cmd[1] = (uint8_t)(SCD4X_MEASURE_SINGLE_SHOT & 0xFF);
        i2c_master_transmit(i2c_device_, cmd, 2, 1000);
        vTaskDelay(pdMS_TO_TICKS(5000));
    }
}

void SCD4X::enablePeriodMeasure(uint8_t mode) {
    uint8_t cmd[2];
    
    switch (mode) {
        case SCD4X_MODE_STOP:
            cmd[0] = (uint8_t)((SCD4X_STOP_PERIODIC_MEASURE >> 8) & 0xFF);
            cmd[1] = (uint8_t)(SCD4X_STOP_PERIODIC_MEASURE & 0xFF);
            break;
        case SCD4X_MODE_PERIODIC:
            cmd[0] = (uint8_t)((SCD4X_START_PERIODIC_MEASURE >> 8) & 0xFF);
            cmd[1] = (uint8_t)(SCD4X_START_PERIODIC_MEASURE & 0xFF);
            break;
        case SCD4X_MODE_LOW_POWER:
            cmd[0] = (uint8_t)((SCD4X_START_LOW_POWER_MEASURE >> 8) & 0xFF);
            cmd[1] = (uint8_t)(SCD4X_START_LOW_POWER_MEASURE & 0xFF);
            break;
        default:
            return;
    }
    
    // Use direct I2C transmission with longer timeout
    i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    vTaskDelay(pdMS_TO_TICKS(50));
}

bool SCD4X::readMeasurement(Measurement* data) {
    // First check if data is ready
    if (!getDataReadyStatus()) {
        return false;
    }

    // Send the read measurement command first
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_READ_MEASUREMENT >> 8) & 0xFF),
        (uint8_t)(SCD4X_READ_MEASUREMENT & 0xFF)
    };
    
    esp_err_t result = i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending read measurement command: %d", result);
        return false;
    }
    
    // Wait a bit before reading
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // Read 9 bytes: CO2 (2 bytes), CRC, Temperature (2 bytes), CRC, Humidity (2 bytes), CRC
    uint8_t buf[9];
    result = i2c_master_receive(i2c_device_, buf, 9, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error reading measurement data: %d", result);
        return false;
    }

    // Check CRC
    if (buf[2] == calcCRC8(buf, 2) && 
        buf[5] == calcCRC8(&buf[3], 2) && 
        buf[8] == calcCRC8(&buf[6], 2)) {
        // Calculate CO2 value
        data->co2_ppm = (buf[0] << 8) | buf[1];
        
        // Calculate temperature value
        uint16_t temp_raw = (buf[3] << 8) | buf[4];
        data->temperature = -45.0f + 175.0f * temp_raw / 65536.0f;
        
        // Calculate humidity value
        uint16_t humid_raw = (buf[6] << 8) | buf[7];
        data->humidity = 100.0f * humid_raw / 65536.0f;
        return true;
    } else {
        ESP_LOGE(TAG, "CRC check failed on measurement data");
    }
    
    return false;
}

bool SCD4X::getDataReadyStatus() {
    // Send the get data ready status command
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_GET_DATA_READY_STATUS >> 8) & 0xFF),
        (uint8_t)(SCD4X_GET_DATA_READY_STATUS & 0xFF)
    };
    
    esp_err_t result = i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending data ready status command: %d", result);
        return false;
    }
    
    // Wait a bit before reading
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // Read 3 bytes: status (2 bytes) and CRC
    uint8_t buf[3];
    result = i2c_master_receive(i2c_device_, buf, 3, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error reading data ready status: %d", result);
        return false;
    }
    
    // Verify CRC
    if (calcCRC8(&buf[0], 2) != buf[2]) {
        ESP_LOGE(TAG, "CRC check failed for data ready status");
        return false;
    }
    
    uint16_t status = (uint16_t)((buf[0] << 8) | buf[1]);
    return (status & 0x07FF) != 0;
}

void SCD4X::setTempComp(float temp_comp) {
    uint16_t temp_offset = (uint16_t)(temp_comp * 65536.0f / 175.0f);
    uint8_t data[5] = {
        (uint8_t)((SCD4X_SET_TEMPERATURE_OFFSET >> 8) & 0xFF),
        (uint8_t)(SCD4X_SET_TEMPERATURE_OFFSET & 0xFF),
        (uint8_t)((temp_offset >> 8) & 0xFF),
        (uint8_t)(temp_offset & 0xFF),
        calcCRC8((uint8_t[]){(uint8_t)((temp_offset >> 8) & 0xFF), (uint8_t)(temp_offset & 0xFF)}, 2)
    };
    
    // For commands with parameters, we need to send all data in one transmission
    i2c_master_transmit(i2c_device_, data, 5, 1000);
}

float SCD4X::getTempComp() {
    // Send the get temperature offset command
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_GET_TEMPERATURE_OFFSET >> 8) & 0xFF),
        (uint8_t)(SCD4X_GET_TEMPERATURE_OFFSET & 0xFF)
    };
    
    esp_err_t result = i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending get temperature offset command: %d", result);
        return 0.0f;
    }
    
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // Read 3 bytes: offset (2 bytes) and CRC
    uint8_t buf[3];
    result = i2c_master_receive(i2c_device_, buf, 3, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error reading temperature offset: %d", result);
        return 0.0f;
    }
    
    if (calcCRC8(&buf[0], 2) != buf[2]) {
        ESP_LOGE(TAG, "CRC check failed for temperature offset");
        return 0.0f;
    }
    
    uint16_t temp_offset = (uint16_t)((buf[0] << 8) | buf[1]);
    return 175.0f * temp_offset / 65536.0f;
}

void SCD4X::setSensorAltitude(uint16_t altitude) {
    uint8_t data[5] = {
        (uint8_t)((SCD4X_SET_SENSOR_ALTITUDE >> 8) & 0xFF),
        (uint8_t)(SCD4X_SET_SENSOR_ALTITUDE & 0xFF),
        (uint8_t)((altitude >> 8) & 0xFF),
        (uint8_t)(altitude & 0xFF),
        calcCRC8((uint8_t[]){(uint8_t)((altitude >> 8) & 0xFF), (uint8_t)(altitude & 0xFF)}, 2)
    };
    
    // For commands with parameters, we need to send all data in one transmission
    i2c_master_transmit(i2c_device_, data, 5, 1000);
}

uint16_t SCD4X::getSensorAltitude() {
    // Send the get sensor altitude command
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_GET_SENSOR_ALTITUDE >> 8) & 0xFF),
        (uint8_t)(SCD4X_GET_SENSOR_ALTITUDE & 0xFF)
    };
    
    esp_err_t result = i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending get sensor altitude command: %d", result);
        return 0;
    }
    
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // Read 3 bytes: altitude (2 bytes) and CRC
    uint8_t buf[3];
    result = i2c_master_receive(i2c_device_, buf, 3, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error reading sensor altitude: %d", result);
        return 0;
    }
    
    if (calcCRC8(&buf[0], 2) != buf[2]) {
        ESP_LOGE(TAG, "CRC check failed for sensor altitude");
        return 0;
    }
    
    return (uint16_t)((buf[0] << 8) | buf[1]);
}

void SCD4X::setAmbientPressure(uint32_t ambient_pressure) {
    uint16_t pressure_hpa = (uint16_t)(ambient_pressure / 100);
    uint8_t data[5] = {
        (uint8_t)((SCD4X_SET_AMBIENT_PRESSURE >> 8) & 0xFF),
        (uint8_t)(SCD4X_SET_AMBIENT_PRESSURE & 0xFF),
        (uint8_t)((pressure_hpa >> 8) & 0xFF),
        (uint8_t)(pressure_hpa & 0xFF),
        calcCRC8((uint8_t[]){(uint8_t)((pressure_hpa >> 8) & 0xFF), (uint8_t)(pressure_hpa & 0xFF)}, 2)
    };
    
    // Send all data in one transmission
    i2c_master_transmit(i2c_device_, data, 5, 1000);
}

void SCD4X::setAutoCalibMode(bool enable) {
    uint16_t value = enable ? 1 : 0;
    uint8_t data[5] = {
        (uint8_t)((SCD4X_SET_AUTOMATIC_CALIB >> 8) & 0xFF),
        (uint8_t)(SCD4X_SET_AUTOMATIC_CALIB & 0xFF),
        (uint8_t)((value >> 8) & 0xFF),
        (uint8_t)(value & 0xFF),
        calcCRC8((uint8_t[]){(uint8_t)((value >> 8) & 0xFF), (uint8_t)(value & 0xFF)}, 2)
    };
    
    // Send all data in one transmission
    i2c_master_transmit(i2c_device_, data, 5, 1000);
}

bool SCD4X::getAutoCalibMode() {
    // Send the get automatic calibration mode command
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_GET_AUTOMATIC_CALIB >> 8) & 0xFF),
        (uint8_t)(SCD4X_GET_AUTOMATIC_CALIB & 0xFF)
    };
    
    esp_err_t result = i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending get auto calib mode command: %d", result);
        return false;
    }
    
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // Read 3 bytes: mode (2 bytes) and CRC
    uint8_t buf[3];
    result = i2c_master_receive(i2c_device_, buf, 3, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error reading auto calib mode: %d", result);
        return false;
    }
    
    if (calcCRC8(&buf[0], 2) != buf[2]) {
        ESP_LOGE(TAG, "CRC check failed for automatic calibration mode");
        return false;
    }
    
    uint16_t value = (uint16_t)((buf[0] << 8) | buf[1]);
    return value != 0;
}

void SCD4X::persistSettings() {
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_PERSIST_SETTINGS >> 8) & 0xFF),
        (uint8_t)(SCD4X_PERSIST_SETTINGS & 0xFF)
    };
    i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    vTaskDelay(pdMS_TO_TICKS(800));
}

bool SCD4X::getSerialNumber(uint16_t serial[3]) {
    // Send the get serial number command
    uint8_t cmd[2] = {
        (uint8_t)((SCD4X_GET_SERIAL_NUMBER >> 8) & 0xFF),
        (uint8_t)(SCD4X_GET_SERIAL_NUMBER & 0xFF)
    };
    
    esp_err_t result = i2c_master_transmit(i2c_device_, cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending get serial number command: %d", result);
        return false;
    }
    
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // Read 9 bytes of serial number data
    uint8_t buf[9];
    result = i2c_master_receive(i2c_device_, buf, 9, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error reading serial number data: %d", result);
        return false;
    }
    
    if (calcCRC8(&buf[0], 2) != buf[2] ||
        calcCRC8(&buf[3], 2) != buf[5] ||
        calcCRC8(&buf[6], 2) != buf[8]) {
        ESP_LOGE(TAG, "CRC check failed for serial number");
        return false;
    }
    
    serial[0] = (uint16_t)((buf[0] << 8) | buf[1]);
    serial[1] = (uint16_t)((buf[3] << 8) | buf[4]);
    serial[2] = (uint16_t)((buf[6] << 8) | buf[7]);
    return true;
}

int16_t SCD4X::performForcedRecalibration(uint16_t co2_ppm) {
    uint8_t data[5] = {
        (uint8_t)((SCD4X_PERFORM_FORCED_RECALIB >> 8) & 0xFF),
        (uint8_t)(SCD4X_PERFORM_FORCED_RECALIB & 0xFF),
        (uint8_t)((co2_ppm >> 8) & 0xFF),
        (uint8_t)(co2_ppm & 0xFF),
        calcCRC8((uint8_t[]){(uint8_t)((co2_ppm >> 8) & 0xFF), (uint8_t)(co2_ppm & 0xFF)}, 2)
    };
    
    // Send all data in one transmission
    esp_err_t result = i2c_master_transmit(i2c_device_, data, 5, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending forced recalibration command: %d", result);
        return 0x7FFF;
    }
    
    vTaskDelay(pdMS_TO_TICKS(400));
    
    // Send the read command to get the result
    uint8_t read_cmd[2] = {
        (uint8_t)((SCD4X_READ_MEASUREMENT >> 8) & 0xFF),
        (uint8_t)(SCD4X_READ_MEASUREMENT & 0xFF)
    };
    
    result = i2c_master_transmit(i2c_device_, read_cmd, 2, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error sending read command for recalibration result: %d", result);
        return 0x7FFF;
    }
    
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // Read 3 bytes: result (2 bytes) and CRC
    uint8_t result_data[3];
    result = i2c_master_receive(i2c_device_, result_data, 3, 1000);
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Error reading recalibration result: %d", result);
        return 0x7FFF;
    }
    
    if (calcCRC8(&result_data[0], 2) != result_data[2]) {
        ESP_LOGE(TAG, "CRC check failed for forced recalibration result");
        return 0x7FFF;
    }
    
    uint16_t correction = (uint16_t)((result_data[0] << 8) | result_data[1]);
    return (int16_t)(correction - 0x8000);
}

uint8_t SCD4X::calcCRC8(const uint8_t* data, uint8_t len) {
    uint8_t crc = SCD4X_CRC8_INIT;
    
    for (uint8_t i = 0; i < len; i++) {
        crc ^= data[i];
        for (uint8_t bit = 8; bit > 0; bit--) {
            if (crc & 0x80) {
                crc = (crc << 1) ^ SCD4X_CRC8_POLYNOMIAL;
            } else {
                crc = (crc << 1);
            }
        }
    }
    
    return crc;
}

#if 0

// 生成简短文件名（FAT32兼容格式，包含日期）
std::string SCD4X::GenerateTimestampLogFilename() {
    // 获取当前时间
    time_t now = time(nullptr);
    struct tm* timeinfo = localtime(&now);
    
    // 生成简短的文件名，格式为 scd4x_MMDD.csv
    char filename[64];
    snprintf(filename, sizeof(filename), "%s/sx%02d%02d.txt", 
             log_path_.c_str(),
             timeinfo->tm_mon + 1, 
             timeinfo->tm_mday);
    
    ESP_LOGI(TAG, "Generated filename: %s", filename);
    return std::string(filename);
}

// 初始化传感器日志记录系统（在系统启动时调用）
bool SCD4X::InitializeSensorDataLogging() {
    ESP_LOGI(TAG, "Initializing SCD4X sensor logging system");
    
    // 检查SD卡是否准备就绪
    if (!sdcard_is_ready()) {
        ESP_LOGW(TAG, "SD card not ready for sensor logging initialization");
        return false;
    }
    
    // 初始化目录结构
    if (!InitializeDirectories()) {
        ESP_LOGE(TAG, "Failed to initialize sensor data directories");
        return false;
    }
    
    // 初始化CSV文件头
    if (!InitializeCSVFile()) {
        ESP_LOGE(TAG, "Failed to initialize CSV file");
        return false;
    }
    
    ESP_LOGI(TAG, "SCD4X sensor logging system initialized successfully");
    return true;
}

// 初始化阶段创建和验证所有需要的目录
bool SCD4X::InitializeDirectories() {
    ESP_LOGI(TAG, "Initializing SCD4X data directory");
    
    // 检查SD卡是否准备就绪
    if (!sdcard_is_ready()) {
        ESP_LOGE(TAG, "SD card not ready");
        return false;
    }

    // 创建并验证目录 - 直接使用sdcard_bsp函数
    esp_err_t result = sdcard_create_directory_recursive(log_path_.c_str());
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Failed to create sensor data directory: %s (error: 0x%x)", log_path_.c_str(), result);
        return false;
    }
    
    // 验证目录权限
    if (access(log_path_.c_str(), W_OK) != 0) {
        int error_code = errno;
        ESP_LOGE(TAG, "Directory not writable: %s (errno: %d - %s)",
                log_path_.c_str(), error_code, strerror(error_code));
        return false;
    }
    
    // 生成基于当天日期的文件名并在初始化时存储
    initialized_filename_ = GenerateTimestampLogFilename();
    ESP_LOGI(TAG, "Initialized filename: %s", initialized_filename_.c_str());
    
    ESP_LOGI(TAG, "Sensor data directory initialized: %s", log_path_.c_str());
    return true;
}

// 创建并验证单个目录
bool SCD4X::CreateAndVerifyDirectory(const std::string& path) {
    ESP_LOGI(TAG, "Creating and verifying directory: %s", path.c_str());
    
    // 使用新的目录创建函数
    esp_err_t result = sdcard_create_directory_recursive(path.c_str());
    if (result != ESP_OK) {
        ESP_LOGE(TAG, "Failed to create directory: %s (error: 0x%x)", path.c_str(), result);
        return false;
    }
    
    // 验证目录权限
    if (access(path.c_str(), W_OK) != 0) {
        int error_code = errno;
        ESP_LOGE(TAG, "Directory not writable: %s (errno: %d - %s)",
                path.c_str(), error_code, strerror(error_code));
        return false;
    }
    
    ESP_LOGI(TAG, "Directory verified successfully: %s", path.c_str());
    return true;
}

// 初始化CSV文件头（如果文件不存在）
bool SCD4X::InitializeCSVFile() {
    
    // 检查文件是否已存在
    struct stat st;
    bool file_exists = (stat(initialized_filename_.c_str(), &st) == 0);
    size_t existing_file_size = file_exists ? st.st_size : 0;
    
    // 以追加模式打开文件（如果不存在会自动创建）
    FILE* file = fopen(initialized_filename_.c_str(), "w");
    if (!file) {
        int error_code = errno;
        ESP_LOGE(TAG, "Failed to create/open data file: %s (errno: %d - %s)", 
                 initialized_filename_.c_str(), error_code, strerror(error_code));
        return false;
    }
    
    // 如果是新文件，写入CSV文件头
    if (!file_exists || existing_file_size == 0) {
        const char* header = "date,timestamp,co2_ppm,temperature_c,humidity_percent\n";
        size_t header_written = fwrite(header, 1, strlen(header), file);
        if (header_written != strlen(header)) {
            ESP_LOGE(TAG, "Failed to write CSV header");
            fclose(file);
            return false;
        }
        ESP_LOGI(TAG, "Created new SCD4X data log file with header: %s", initialized_filename_.c_str());
    } else {
        ESP_LOGI(TAG, "Using existing SCD4X data log file: %s (size: %d bytes)", 
                 initialized_filename_.c_str(), existing_file_size);
    }
    fclose(file);

    return true;
}

// ESP32定时器回调函数
void SCD4X::TimerCallback(void* arg) {
    if (arg != nullptr) {
        SCD4X* instance = static_cast<SCD4X*>(arg);
        if (instance->is_logging_ && sdcard_is_ready()) {
            // 读取传感器数据
            if (instance->getDataReadyStatus()) {
                // 直接调用SaveCurrentDataToFile，使用内部初始化的文件名
                if (instance->SaveCurrentData()) {
                    ESP_LOGI(TAG, "SCD4X data appended to: %s", instance->GetInitializedFilename().c_str());
                } else {
                    ESP_LOGE(TAG, "Failed to append SCD4X data to: %s", instance->GetInitializedFilename().c_str());
                }
            } else {
                ESP_LOGW(TAG, "SCD4X data not ready");
            }
        }
    }
}

// 启动定时数据记录
bool SCD4X::StartTimedLogging(int interval_seconds) {
    // 先停止当前可能正在运行的定时器
    StopTimedLogging();
    
    // 检查SD卡是否准备就绪
    if (!sdcard_is_ready()) {
        ESP_LOGE(TAG, "SD card not ready");
        return false;
    }
    
    interval_seconds_ = interval_seconds;
    
    // 检查目录和文件是否已初始化
    if (initialized_filename_.empty()) {
        ESP_LOGW(TAG, "Sensor logging not properly initialized, attempting to initialize now");
        if (!InitializeSensorDataLogging()) {
            ESP_LOGE(TAG, "Failed to initialize sensor logging");
            return false;
        }
    }
    
    // 创建ESP32定时器
    const esp_timer_create_args_t timer_args = {
        .callback = &TimerCallback,
        .arg = this,
        .name = "SCD4X"
    };
    
    esp_err_t err = esp_timer_create(&timer_args, &timer_);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to create timer: %s", esp_err_to_name(err));
        return false;
    }
    
    // 启动周期性定时器（单位：微秒）
    err = esp_timer_start_periodic(timer_, interval_seconds_ * 1000000LL);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to start timer: %s", esp_err_to_name(err));
        esp_timer_delete(timer_);
        timer_ = nullptr;
        return false;
    }
    
    is_logging_ = true;
    ESP_LOGI(TAG, "Timed data logging started: interval=%ds, path=%s", 
             interval_seconds_, log_path_.c_str());
    return true;
}

// 停止定时数据记录
void SCD4X::StopTimedLogging() {
    if (timer_ != nullptr) {
        esp_timer_stop(timer_);
        esp_timer_delete(timer_);
        timer_ = nullptr;
    }
    is_logging_ = false;
    ESP_LOGI(TAG, "Timed data logging stopped");
}



// 实际保存数据到文件的函数
bool SCD4X::SaveCurrentData() {
    // 检查传感器数据是否就绪
    if (!getDataReadyStatus()) {
        ESP_LOGE(TAG, "SCD4X data not ready");
        return false;
    }

    // 读取传感器数据
    SCD4X::Measurement data;
    readMeasurement(&data);   

     if (initialized_filename_.empty()) {
        ESP_LOGW(TAG, "Sensor logging not properly initialized, attempting to initialize now");
        if (!InitializeSensorDataLogging()) {
            ESP_LOGE(TAG, "Failed to initialize sensor logging");
            return false;
        }
    }
    
    // 以追加模式打开文件
    FILE* file = fopen(initialized_filename_.c_str(), "a");
    if (!file) {
        int error_code = errno;
        ESP_LOGE(TAG, "Failed to open file for appending: %s (errno: %d - %s)", 
                 initialized_filename_.c_str(), error_code, strerror(error_code));
        return false;
    }

    // 生成数据行
    time_t now = time(nullptr);
    struct tm* timeinfo = localtime(&now);
    
    char data_row[256];
    int row_length = snprintf(data_row, sizeof(data_row), 
             "%04d-%02d-%02d,%02d:%02d:%02d,%d,%.2f,%.2f\n",
             timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
             timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec,
             data.co2_ppm, data.temperature, data.humidity);
    
    // 写入数据行
    size_t row_written = fwrite(data_row, 1, row_length, file);
    fclose(file);
    
    if (row_written != row_length) {
        ESP_LOGE(TAG, "Failed to append CSV data row - wrote %d of %d bytes", row_written, row_length);
        return false;
    }
    
    ESP_LOGI(TAG, "Successfully appended data entry to %s", initialized_filename_.c_str());
    return true;
}
#endif